/*
 * 
 */
package com.pentalog.rest.httpclient;


import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.ws.rs.core.MediaType;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.codehaus.jackson.map.ObjectMapper;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * The Class RestClientWSUtil.
 * @author tnguyenmanh
 * @version 1.0
 */
public class RestClientWSUtil {

    /** The Constant LOGGER. */
    private static final Logger LOGGER = LoggerFactory.getLogger(RestClientWSUtil.class);

    /** The Constant TMP_DIR. */
    private static final String TMP_DIR = "java.io.tmpdir";
    
    /** The Constant XML_FILE_SUFFIX. */
    private static final String XML_FILE_SUFFIX = ".xml";
    
    /**
     * Call http json web service.
     *
     * @param <T> the generic type for JSON object
     * @param clazz the clazz
     * @param httpURLString the http url string
     * @return the t
     * @throws IOException Signals that an I/O exception has occurred.
     */
    public static <T> T callHTTPJSONWebService(final Class<T> clazz, final String httpURLString) throws IOException {
       
    	/**
    	 * Connect to webservice and execute the request
    	 */
    	HttpClient httpClient = new DefaultHttpClient();
        HttpGet httpget = new HttpGet(httpURLString);      
        HttpResponse response = httpClient.execute(httpget);
        
        if (response.getStatusLine().getStatusCode() != 200) {
			throw new IOException("Failed : HTTP error code : "
					+ response.getStatusLine().getStatusCode());
		}

        /**
         * Convert return input stream to Json object by using Jackson library
         */
        ObjectMapper mapper = new ObjectMapper();
        T jsonObject = mapper.readValue(response.getEntity().getContent(), clazz);
        
       /**
        * Close the connection with server web service
        */
        httpClient.getConnectionManager().shutdown();
     
        return jsonObject;
    }
    
    
    /**
     * Call httpxml web service.
     *
     * @param <T> the generic type (JAXB object, note : must have registered in ObjectFactory in package)
     * @param clazz the clazz
     * @param httpURLString the http url string
     * @return the t
     * @throws IOException Signals that an I/O exception has occurred.
     */
    public static <T> T callHTTPXMLWebService(final Class<T> clazz, final String httpURLString) throws IOException {
        HttpClient httpclient = new DefaultHttpClient();
        HttpGet httpget = new HttpGet(httpURLString);      

        JAXBElement<T> element = null;
        try {
        	
        	
            final JAXBContext context = JAXBContext.newInstance(clazz.getPackage().getName());
            final Unmarshaller unmarshaller = context.createUnmarshaller();

            element = unmarshaller.unmarshal(new StreamSource(httpclient.execute(httpget).getEntity().getContent()), clazz);
        } catch (final JAXBException e) {
            LOGGER.error(e.getMessage(), e);
            throw new IOException("Exception during execution of web service, please contact with the service vendor...", e);
        } finally {
            httpclient.getConnectionManager().shutdown();
        }
        return element.getValue();
    }


    /**
     * Call httpxml web service.
     *
     * @param fileName the file name
     * @param httpURLString the http url string
     * @return the file
     * @throws IOException Signals that an I/O exception has occurred.
     * @throws Exception the exception
     */
    public static File callHTTPXMLWebService(final String fileName, final String httpURLString) throws IOException,
            Exception {
        return callHTTPXMLWebService(fileName, httpURLString, new DefaultHttpClient());
    }

    /**
     * Call httpxml web service.
     *
     * @param fileName the file name
     * @param httpURLString the http url string
     * @param client the client
     * @return the file
     * @throws IOException Signals that an I/O exception has occurred.
     * @throws Exception the exception
     */
    public static File callHTTPXMLWebService(final String fileName, final String httpURLString, HttpClient client)
            throws IOException, Exception {
        File xmlFile = null;
        InputStream in = null;
        FileOutputStream out = null;
        try {
            LOGGER.info("Calling REST Services. URL: {} ", httpURLString);
            HttpGet get = new HttpGet(httpURLString);
            get.setHeader("Content-Type", MediaType.TEXT_XML);
            HttpResponse response = client.execute(get);
            LOGGER.debug("Response: {}, Code: {}", response.getStatusLine().getReasonPhrase(),
                    response.getStatusLine().getStatusCode());
            if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK || response.getEntity() == null) {
                StringBuilder error = new StringBuilder("Error calling the REST Services : ").append(httpURLString);
                error.append("\n -> Response recieved: ").append(response.getStatusLine().getReasonPhrase());
                error.append(", Status Code:  ").append(response.getStatusLine().getStatusCode());
                throw new Exception(error.toString());
            }

            xmlFile = new File(System.getProperty(TMP_DIR) + File.separator + fileName + XML_FILE_SUFFIX);
            out = new FileOutputStream(xmlFile);
            response.getEntity().writeTo(out);
            LOGGER.debug("File is stored in {}", xmlFile);
            return xmlFile;
        } finally {
            if (out != null) {
                out.close();
            }
            if (in != null) {
                in.close();
            }
        }

    }
}
